with Ada.Command_Line;
with Ada.IO_Exceptions;


package body Bulletins.Io is

   -- PROCEDURE INTERENE Permet la saisie de l'objectif du bulletin.
   procedure GetObjectif(b : in out Bulletin) is
   begin
      Valeur.Io.Get("Valeur pour l'Objectif : ", b.Un_Objectif);
   exception
      when e : Ada.Text_IO.Data_Error => raise saisieIncorrecte with "Saisie de l'objectif du bulletin incorrecte.";
   end GetObjectif;


   -- PROCEDURE INTERENE Permet la saisie d'une nouvelle matiere et l'ajouter au bulletin.
   procedure GetMatiere(b : in out Bulletin) is
      m : Matieres.Matiere;
   begin
      Matieres.Io.Get("Saisie de la nouvelle matiere :", m);
      b := Bulletins.Enregistrer(b, m);
   exception
      when e : Matiere_deja_existante => raise saisieIncorrecte with Ada.Exceptions.Exception_Message(e);
      when e : Matieres.Intitule_trop_long => raise saisieIncorrecte with Ada.Exceptions.Exception_Message(e);
   end GetMatiere;


   -- PROCEDURE INTERENE Permet la modification/suppression d'une matiere du bulletin.
   procedure ModifMatiere(b : in out Bulletin) is
      m :Matieres.Matiere;
      indice : Nombre := 0;
   begin
      Ada.Text_IO.Put_Line("Saisir l'intitule de la matiere a modifier/supprimer : ");
      m := Matieres.construct(Ada.Text_IO.Get_Line); ------------------------------- excpetion à gérer
      indice := indiceMatiere(b, Matieres.getIntitule(m));
      if indice = 0 then
         raise saisieIncorrecte with "Matiere introuvable.";
      end if;
      mainLoop : loop
         declare
            subtype choixMenu is natural range 1 .. 7;
            choix : choixMenu;
            v : Valeur.Valeur;
         begin
            Ada.Text_IO.New_Line;
            Ada.Text_IO.Put_Line("Modification de " & Matieres.getIntitule(m) & " : ");
            Ada.Text_IO.Put_Line("1. Afficher matiere");
            Ada.Text_IO.Put_Line("2. Liberer la note de la matiere");
            Ada.Text_IO.Put_Line("3. Simuler la note de la matiere");
            Ada.Text_IO.Put_Line("4. Attribuer la note de la matiere");
            Ada.Text_IO.Put_Line("5. Modifier la note de la matiere");
            Ada.Text_IO.Put_Line("6. Supprimer la matiere");
            Ada.Text_IO.Put_Line("7. Terminer la modification de la matiere");
            choix := choixMenu'Value(Ada.Text_IO.Get_Line);
            Ada.Text_IO.New_Line;
            Ada.Text_IO.New_Line;
            Ada.Text_IO.New_Line;
            Ada.Text_IO.New_Line;
            case choix is
               when 1 => Matieres.Io.Put(b.Des_Matieres(indice));
               when 2 => LibererNoteMatiere(b, Matieres.getIntitule(m));
               when 3 =>
                  Valeur.Io.Get("Saisir une valeur pour simuler la note :", v);
                  SimulerNoteMatiere(b, Matieres.getIntitule(m), v);
               when 4 =>
                  Valeur.Io.Get("Saisir une valeur pour attribuer la note :", v);
                  AttribuerNoteMatiere(b, Matieres.getIntitule(m), v);
               when 5 =>
                  Valeur.Io.Get("Saisir une valeur pour modifier la note :", v);
                  ModifierNoteMatiere(b, Matieres.getIntitule(m), v);
               when 6 =>
                  b := Retirer(b, Matieres.getIntitule(m));
                  exit mainLoop;
                  when 7 =>
                  Ada.Text_IO.Put_Line("Saisie du bulletin terminee.");
                  exit mainLoop;
            end case;
         exception
            when e : saisieIncorrecte => Ada.Text_IO.Put_Line(Ada.Exceptions.Exception_Message(e));
            when e : Matiere_introuvable => Ada.Text_IO.Put_Line(Ada.Exceptions.Exception_Message(e));
            when e : Deja_attribuee => Ada.Text_IO.Put_Line(Ada.Exceptions.Exception_Message(e));
            when e : Non_attribuee => Ada.Text_IO.Put_Line(Ada.Exceptions.Exception_Message(e));
         end;
      end loop mainLoop;
   end ModifMatiere;



   -- Affichage d'un bulletin.
   procedure Put(b : in Bulletin) is
      LeBilan : Bulletins.Bilan.Bilan;
   begin
      Ada.Text_IO.Put_Line("Bulletin (" & Nombre'Image(b.Selon) & " matieres)");
      Ada.Text_IO.New_Line;
      Ada.Text_IO.Put_Line("Les Matieres :");
      for i in b.Des_Matieres'Range loop
         Ada.Text_IO.New_Line;
         Matieres.Io.Put(b.Des_Matieres(i));
      end loop;
      Ada.Text_IO.New_Line;
      Ada.Text_IO.Put_Line("Le Bilan :");
      LeBilan := Bulletins.Bilan.Resumer(b);
      if Bulletins.Bilan.getUnEtatMoyenne(LeBilan) = Bulletins.Bilan.Effective then
         Ada.Text_IO.Put("Moyenne effective : ");
         Valeur.Io.Put(Bulletins.Bilan.getMoyenne(LeBilan));
      elsif Bulletins.Bilan.getUnEtatMoyenne(LeBilan) = Bulletins.Bilan.AObtenir then
         Ada.Text_IO.Put("Moyenne a obtenir pour satisfaire l'objectif du bulletin : ");
         Valeur.Io.Put(Bulletins.Bilan.getMoyenne(LeBilan));
      else
         Ada.Text_IO.Put("Moyenne la plus proche de l'objectif : ");
         Valeur.Io.Put(Bulletins.Bilan.getMoyenne(LeBilan));
      end if;
      Ada.Text_IO.New_Line;
      Ada.Text_IO.Put("Objectif : ");
      Valeur.Io.Put(b.Un_Objectif);
      Ada.Text_IO.New_Line;
      if (b.Un_Objectif <= Bulletins.Bilan.getMoyenne(LeBilan))then
         Ada.Text_IO.put("objectif atteint");
      else
         Ada.Text_IO.put("objectif non atteint");
      end if;
      Ada.Text_IO.New_Line;

   end Put;


   -- Saisie d'un bulletin;
   procedure Get(Message : in String; b : out Bulletin) is
   begin
      mainLoop : loop
         declare
            subtype choixMenu is natural range 1 .. 6;
            choix : choixMenu;
         begin
            Ada.Text_IO.New_Line;
            Ada.Text_IO.Put_Line(Message);
            Ada.Text_IO.Put_Line("1. Lister le bulletin");
            Ada.Text_IO.Put_Line("2. Classer le bulletin");
            Ada.Text_IO.Put_Line("3. Viser l'objectif du bulletin");
            Ada.Text_IO.Put_Line("4. Ajouter une matiere au bulletin");
            Ada.Text_IO.Put_Line("5. Modifier/Supprimer une matiere du bulletin");
            Ada.Text_IO.Put_Line("6. Terminer la saisie du bulletin");
            choix := choixMenu'Value(Ada.Text_IO.Get_Line);
            Ada.Text_IO.New_Line;
            Ada.Text_IO.New_Line;
            Ada.Text_IO.New_Line;
            Ada.Text_IO.New_Line;
            case choix is
               when 1 => Put( b);
               when 2 => Classer(b, Matieres.Classement.Io.Priorite("Classement de matieres"));
               when 3 => GetObjectif(b);
               when 4 => GetMatiere(b);
               when 5 => ModifMatiere(b);
               when 6 =>
                  Ada.Text_IO.Put_Line("Saisie du bulletin terminee.");
                  exit mainLoop;
            end case;
         exception
            when e : saisieIncorrecte => Ada.Text_IO.Put_Line(Ada.Exceptions.Exception_Message(e));
            when e : constraint_error => null;
         end;
      end loop mainLoop;
   end Get;

   -- Ecriture d'un bulletin dans un fichier
   procedure Put(Un_Fichier : in Ada.Text_IO.File_Type; b : in Bulletin) is
   begin
      Nombre_Io.put(Un_Fichier, b.selon);
      Ada.Text_IO.New_Line(Un_Fichier);
      Valeur.Io.Put(Un_Fichier, b.Un_Objectif);
      Ada.Text_IO.New_Line(Un_Fichier);

      for i in b.Des_Matieres'range loop
         Matieres.Io.Put(Un_Fichier, b.Des_Matieres(i));
      end loop;
   end Put;

   -- Lecture d'un bulletin dans un fichier
   procedure Get(Un_Fichier : in Ada.Text_IO.File_Type; b : out Bulletin) is
      Nombre_Matieres : Nombre;
      Matiere_Aux : Matieres.Matiere;
      Bulletin_Fichier : Bulletin;
   begin
      Nombre_Io.Get(Un_Fichier, Nombre_Matieres);
      Ada.Text_IO.Skip_Line(Un_Fichier);
      Valeur.Io.Get(Un_Fichier, Bulletin_Fichier.Un_Objectif);

      for i in 1..Nombre_Matieres loop
         Matieres.Io.Get(Un_Fichier, Matiere_Aux);
         Bulletin_Fichier := Enregistrer(Bulletin_Fichier, Matiere_Aux);
      end loop;

      b := Bulletin_Fichier;
   end Get;

   -- Initialise le bulletin à partir du fichier passé en paramèttre de l'application
   procedure Charger(b : out Bulletin) is
      F_Bulletin : Ada.Text_IO.File_Type;
   begin
      if Ada.Command_Line.Argument_Count > 0 then

         Ada.Text_IO.Open(File => F_Bulletin,
                          Mode => Ada.Text_IO.In_File,
                          Name => Ada.Command_Line.Argument(1));

         Get(F_Bulletin, b);

         Ada.Text_IO.Close(F_Bulletin);
      end if;
   exception
      when Ada.Text_IO.Name_Error =>
         Ada.Text_IO.Put_Line("Le bulletin n'a pas ete initialise : nom de fichier incorrect ou inexistant.");
      when Ada.IO_Exceptions.Data_Error | Ada.IO_Exceptions.End_Error =>
         Ada.Text_IO.Close(F_Bulletin);
         Ada.Text_IO.Put_Line("Le bulletin n'a pas ete initialise : fichier corrompu.");
   end Charger;

   -- Sauvegarde le bulletin dans le fichier passé en paramèttre de l'application
   procedure Sauvegarder(b : in Bulletin) is
      F_Bulletin : Ada.Text_IO.File_Type;
   begin
      if Ada.Command_Line.Argument_Count > 0 then
         Ada.Text_IO.Create(File => F_Bulletin,
                            Mode => Ada.Text_IO.Out_File,
                            Name => Ada.Command_Line.Argument(1));

         Put(F_Bulletin, b);

         Ada.Text_IO.Close(F_Bulletin);
      end if;
   exception
      when ada.Text_IO.Name_Error =>
         Ada.Text_IO.Put_Line("Le bulletin n'a pas ete sauvegarde : nom de fichier incorrect.");
   end Sauvegarder;

end Bulletins.Io;
